package cn.chenbonian.crowdfunding.mvc.config;

import cn.chenbonian.crowdfunding.constant.CrowdConstant;
import cn.chenbonian.crowdfunding.exception.LoginAcctAlreadyInUseException;
import cn.chenbonian.crowdfunding.exception.LoginAcctAlreadyInUseForUpdateException;
import cn.chenbonian.crowdfunding.exception.LoginFailedException;
import cn.chenbonian.crowdfunding.util.CrowdUtil;
import cn.chenbonian.crowdfunding.util.ResultEntity;
import com.google.gson.Gson;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @author chbn
 * @create 2020-05-06 14:35
 */

// @ControllerAdvice 表示当前类是一个基于注解的异常处理器类
@ControllerAdvice
public class CrowdExceptionResolver {

  @ExceptionHandler(value = LoginAcctAlreadyInUseForUpdateException.class)
  public ModelAndView resolveLoginAcctAlreadyInUseForUpdateException(
      LoginAcctAlreadyInUseForUpdateException exception,
      HttpServletRequest request,
      HttpServletResponse response)
      throws IOException {
    String viewName = "system-error";
    return commonResolve(viewName, exception, request, response);
  }

  @ExceptionHandler(value = LoginAcctAlreadyInUseException.class)
  public ModelAndView resolveLoginAcctAlreadyInUseException(
      LoginAcctAlreadyInUseException exception,
      HttpServletRequest request,
      HttpServletResponse response)
      throws IOException {
    String viewName = "admin-add";
    return commonResolve(viewName, exception, request, response);
  }

  @ExceptionHandler(value = LoginFailedException.class)
  public ModelAndView resolveLoginFailedException(
      LoginFailedException exception, HttpServletRequest request, HttpServletResponse response)
      throws IOException {
    String viewName = "admin-login";
    return commonResolve(viewName, exception, request, response);
  }

  @ExceptionHandler(value = Exception.class)
  public ModelAndView resolveAccessForbiddenException(
      Exception exception, HttpServletRequest request, HttpServletResponse response)
      throws IOException {
    String viewName = "admin-login";
    return commonResolve(viewName, exception, request, response);
  }

  // @ExceptionHandler 将一个具体的异常类型和一个方法关联起来
  @ExceptionHandler(value = NullPointerException.class)
  public ModelAndView resolveNullPointException(
      NullPointerException exception, HttpServletRequest request, HttpServletResponse response)
      throws IOException {
    String viewName = "system-error";
    // 11. 返回ModelAndView对象
    return commonResolve(viewName, exception, request, response);
  }

  private ModelAndView commonResolve(
      String viewName,
      Exception exception,
      HttpServletRequest request,
      HttpServletResponse response)
      throws IOException {
    // 1.
    boolean judgeResult = CrowdUtil.judgeRequestType(request);
    //
    if (judgeResult) {
      // 3.创建ResultEntity对象
      ResultEntity<Object> resultEntity = ResultEntity.failed(exception.getMessage());
      // 4. 创建Gson对象
      Gson gson = new Gson();
      // 5. 将resultEntity对象转换为JSON字符串
      String json = gson.toJson(resultEntity);
      // 6. 将JSON字符串作为响应体返回给浏览器
      response.getWriter().write(json);
      // 7. 由于上面已经通过原生的response对象返回了响应，所以不提供ModelAndView对象
      return null;
    }
    // 8. 如果不是Ajax请求，则先创建ModelAndView对象
    ModelAndView modelAndView = new ModelAndView();
    // 9. 将Exception对象存入模型
    modelAndView.addObject(CrowdConstant.ATTR_NAME_EXCEPTION, exception);
    // 10. 设置对应的视图名称
    modelAndView.setViewName(viewName);
    // 11. 返回modelAndView对象
    return modelAndView;
  }
}
